﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace testServ
{
    
    class Program
    {
        static void Main(string[] args)
        {
            var c = new serwer();//tworze obiekt klasy serwera 
            while (true)
            {
                string id = Console.ReadLine();//podaje id klienta
                string info = Console.ReadLine();//podaje wiadomosc
                c.send(id, info);//wysylam ddo klienta
            }
        }



    }

    class serwer
    {
        public void send(String id, String info)//metoda do wysylania
        {
            byte[] byData = System.Text.Encoding.ASCII.GetBytes(info);
            Console.WriteLine(id + "to sent");
            _sockets[id].BeginSend(byData, 0, byData.Length, SocketFlags.None, null, null);//wybieram socket klienta po jego Id ze slownika _sockets
        }
        public serwer()
        {
            StartListening();//kkkk tutaj zaczynam nasluch
        }

        private Dictionary<String, Socket> _sockets = new Dictionary<string, Socket>();//tutaj slownik socketow klientow mapuje id na socket

        public Socket m_socListener;
        public void StartListening()//no tuuu
        {
            try
            {
                //create the listening socket...
                m_socListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 8221);
                //bind to local IP Address...
                m_socListener.Bind(ipLocal);
                //start listening...
                m_socListener.Listen(4);
                // create the call back for any client connections...
                m_socListener.BeginAccept(new AsyncCallback(OnClientConnect), null);//socket serwera ustawiony i wlacza asyn accepp
                                                                                    //pkkk skacze do onclientconnecy po zakceptowaniu pieerwszego clietna
            }
            catch (SocketException se)
            {
                throw new Exception("Listening failed");
            }
        }

        public void OnClientConnect(IAsyncResult asyn)//kk mamy metode gdy zaakceptujemy klienta
        {
            try
            {
                var mSocClient = m_socListener.EndAccept(asyn);//akceptujemy klienta i dostajemy jego socket
                mSocClient.BeginReceive(m_DataBuffer, 0, m_DataBuffer.Length, SocketFlags.None, OnIdReceived, mSocClient);//wlaczamy na nim receive specjalnego
                 //specjalnego receive bo musimy najpierw id odebrac
            }
            catch (ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
            }
            m_socListener.BeginAccept(new AsyncCallback(OnClientConnect), null);
        }

        public void OnDataReceived(IAsyncResult asyn)//o tutaj
        {
            //end receive...
            String id = (String)asyn.AsyncState;//odczytuje id socketa
            var mSocClient = _sockets[id];//wybierma ze slownika i standard
            int iRx = 0;
            iRx = mSocClient.EndReceive(asyn);
            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(m_DataBuffer, 0, iRx, chars, 0);
            System.String szData = new System.String(chars);
            mSocClient.BeginReceive(m_DataBuffer, 0, m_DataBuffer.Length, SocketFlags.None, OnDataReceived, id);
        }
        public void OnIdReceived(IAsyncResult asyn)//o tutaj skaczemy
        {
            //end receive...
            var mSocClient = (Socket)asyn.AsyncState;//tutaj przekazalem socket przez asyncstate
            int iRx = 0;
            iRx = mSocClient.EndReceive(asyn);
            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(m_DataBuffer, 0, iRx, chars, 0);
            System.String id = new System.String(chars);//odebralem Id //kk mam id
            _sockets[id.TrimEnd('\0')] = mSocClient; // przypusuje socket do slownika po id//usuwam na koncu /0 bo sockety to dodaja nieptorzebnie ;p
            Console.WriteLine(id + " Connected " + _sockets.Count);
            mSocClient.BeginReceive(m_DataBuffer, 0, m_DataBuffer.Length, SocketFlags.None, OnDataReceived, id);//no i jak juz odebralem id
            //i dodalem socket do slownika z id to rozpoczynam normalnego receive na zwykle dane OnDataReceived ooo i jako async state
            //przekazuje id, bo musze wiedziec ktory socket wywolal OnDataReceived
        }

        byte[] m_DataBuffer = new byte[10];
    }
}
